From: Colin Walters Date: Tue, 1 Jul 2025 14:54:52 +0000 (-0400) Subject: sysroot: Cache deployment device/inode X-Git-Tag: archive/raspbian/2025.7-2+rpi1^2^2~6^2~4^2~9^2 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22%22/%22http:/www.example.com/cgi/%22https:/%22%22?a=commitdiff_plain;h=d41c2c24b0aabc8e0e5aaa8387a6f38111b58f71;p=ostree.git sysroot: Cache deployment device/inode This is a lot cleaner. In particular, it's prep for having soft reboot finalize at shutdown time, because we weren't correctly handling the staged deployment in that case. To implement this we need to basically stop using ostree_deployment_new() in most places, and instead ensure that all callers use this path which cache the device/inode. Signed-off-by: Colin Walters --- diff --git a/src/libostree/ostree-deployment-private.h b/src/libostree/ostree-deployment-private.h index 55a3bded..367f68ea 100644 --- a/src/libostree/ostree-deployment-private.h +++ b/src/libostree/ostree-deployment-private.h @@ -55,6 +55,11 @@ struct _OstreeDeployment gboolean soft_reboot_target; char **overlay_initrds; char *overlay_initrds_id; + + // Private cache of expected backing device/inode + gboolean devino_initialized; + dev_t device; + ino_t inode; }; void _ostree_deployment_set_bootcsum (OstreeDeployment *self, const char *bootcsum); diff --git a/src/libostree/ostree-deployment.c b/src/libostree/ostree-deployment.c index b4427262..a11efe55 100644 --- a/src/libostree/ostree-deployment.c +++ b/src/libostree/ostree-deployment.c @@ -255,6 +255,10 @@ ostree_deployment_clone (OstreeDeployment *self) OstreeDeployment *ret = ostree_deployment_new ( self->index, self->osname, self->csum, self->deployserial, self->bootcsum, self->bootserial); + ret->devino_initialized = TRUE; + ret->device = self->device; + ret->inode = self->inode; + new_bootconfig = ostree_bootconfig_parser_clone (self->bootconfig); ostree_deployment_set_bootconfig (ret, new_bootconfig); diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c index 5d44af45..6d2accde 100644 --- a/src/libostree/ostree-sysroot-cleanup.c +++ b/src/libostree/ostree-sysroot-cleanup.c @@ -32,8 +32,8 @@ * @inout_deployments: All deployments in this subdir will be appended to this array */ gboolean -_ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd, const char *osname, - GPtrArray *inout_deployments, +_ostree_sysroot_list_deployment_dirs_for_os (OstreeSysroot *self, int deploydir_dfd, + const char *osname, GPtrArray *inout_deployments, GCancellable *cancellable, GError **error) { g_auto (GLnxDirFdIterator) dfd_iter = { @@ -63,8 +63,11 @@ _ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd, const char *osna if (!_ostree_sysroot_parse_deploy_path_name (dent->d_name, &csum, &deployserial, error)) return FALSE; - g_ptr_array_add (inout_deployments, - ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1)); + OstreeDeployment *deploy = _ostree_sysroot_new_deployment_object ( + self, osname, csum, deployserial, NULL, -1, error); + if (!deploy) + return FALSE; + g_ptr_array_add (inout_deployments, deploy); } return TRUE; @@ -100,8 +103,8 @@ list_all_deployment_directories (OstreeSysroot *self, GPtrArray **out_deployment if (dent->d_type != DT_DIR) continue; - if (!_ostree_sysroot_list_deployment_dirs_for_os (dfd_iter.fd, dent->d_name, ret_deployments, - cancellable, error)) + if (!_ostree_sysroot_list_deployment_dirs_for_os (self, dfd_iter.fd, dent->d_name, + ret_deployments, cancellable, error)) return FALSE; } diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 2d676be1..2a674326 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -3033,8 +3033,8 @@ allocate_deployserial (OstreeSysroot *self, const char *osname, const char *revi if (!glnx_opendirat (self->sysroot_fd, "ostree/deploy", TRUE, &deploy_dfd, error)) return FALSE; - if (!_ostree_sysroot_list_deployment_dirs_for_os (deploy_dfd, osname, tmp_current_deployments, - cancellable, error)) + if (!_ostree_sysroot_list_deployment_dirs_for_os (self, deploy_dfd, osname, + tmp_current_deployments, cancellable, error)) return FALSE; for (guint i = 0; i < tmp_current_deployments->len; i++) @@ -3206,6 +3206,13 @@ sysroot_initialize_deployment (OstreeSysroot *self, const char *osname, const ch &checkout_elapsed, &composefs_elapsed, cancellable, error)) return FALSE; + struct stat stbuf; + if (fstat (deployment_dfd, &stbuf) < 0) + return glnx_throw_errno_prefix (error, "fstat(deployment fd)"); + new_deployment->devino_initialized = TRUE; + new_deployment->device = stbuf.st_dev; + new_deployment->inode = stbuf.st_ino; + g_autoptr (OstreeKernelLayout) kernel_layout = NULL; if (!get_kernel_from_tree (self, deployment_dfd, &kernel_layout, cancellable, error)) return FALSE; @@ -3651,7 +3658,8 @@ require_str_key (GVariantDict *dict, const char *name, const char **ret, GError * higher level code. */ OstreeDeployment * -_ostree_sysroot_deserialize_deployment_from_variant (GVariant *v, GError **error) +_ostree_sysroot_deserialize_deployment_from_variant (OstreeSysroot *self, GVariant *v, + GError **error) { g_autoptr (GVariantDict) dict = g_variant_dict_new (v); const char *name = NULL; @@ -3667,7 +3675,8 @@ _ostree_sysroot_deserialize_deployment_from_variant (GVariant *v, GError **error gint deployserial; if (!_ostree_sysroot_parse_deploy_path_name (name, &checksum, &deployserial, error)) return NULL; - return ostree_deployment_new (-1, osname, checksum, deployserial, bootcsum, -1); + return _ostree_sysroot_new_deployment_object (self, osname, checksum, deployserial, bootcsum, -1, + error); } /** @@ -4000,7 +4009,7 @@ _ostree_sysroot_finalize_staged_inner (OstreeSysroot *self, GCancellable *cancel &merge_deployment_v)) { g_autoptr (OstreeDeployment) merge_deployment_stub - = _ostree_sysroot_deserialize_deployment_from_variant (merge_deployment_v, error); + = _ostree_sysroot_deserialize_deployment_from_variant (self, merge_deployment_v, error); if (!merge_deployment_stub) return FALSE; for (guint i = 0; i < self->deployments->len; i++) diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index 6370592f..1ca12c26 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -128,6 +128,12 @@ struct OstreeSysroot gboolean _ostree_sysroot_ensure_writable (OstreeSysroot *self, GError **error); +// Should be preferred over ostree_deployment_new +OstreeDeployment *_ostree_sysroot_new_deployment_object (OstreeSysroot *self, const char *osname, + const char *csum, int deployserial, + const char *bootcsum, int bootserial, + GError **error); + void _ostree_sysroot_emit_journal_msg (OstreeSysroot *self, const char *msg); gboolean _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, int bootversion, @@ -141,7 +147,8 @@ gboolean _ostree_sysroot_read_current_subbootversion (OstreeSysroot *self, int b gboolean _ostree_sysroot_parse_deploy_path_name (const char *name, char **out_csum, int *out_serial, GError **error); -gboolean _ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd, const char *osname, +gboolean _ostree_sysroot_list_deployment_dirs_for_os (OstreeSysroot *self, int deploydir_dfd, + const char *osname, GPtrArray *inout_deployments, GCancellable *cancellable, GError **error); @@ -157,7 +164,8 @@ gboolean _ostree_sysroot_boot_complete (OstreeSysroot *self, GCancellable *cance gboolean _ostree_prepare_soft_reboot (GError **error); -OstreeDeployment *_ostree_sysroot_deserialize_deployment_from_variant (GVariant *v, GError **error); +OstreeDeployment *_ostree_sysroot_deserialize_deployment_from_variant (OstreeSysroot *self, + GVariant *v, GError **error); char *_ostree_sysroot_get_deployment_backing_relpath (OstreeDeployment *deployment); diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index f9955ce2..e861b716 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -826,6 +826,31 @@ _ostree_sysroot_get_runstate_path (OstreeDeployment *deployment, const char *key ostree_deployment_get_deployserial (deployment), key); } +// Should be preferred over ostree_deployment_new as this also initializes cached +// state for device/inode. +OstreeDeployment * +_ostree_sysroot_new_deployment_object (OstreeSysroot *self, const char *osname, const char *csum, + int deployserial, const char *bootcsum, int bootserial, + GError **error) +{ + if (!ensure_sysroot_fd (self, error)) + return FALSE; + + // This deployment isn't associated with an index. + g_autoptr (OstreeDeployment) ret + = ostree_deployment_new (-1, osname, csum, deployserial, bootcsum, bootserial); + + g_autofree char *relpath = ostree_sysroot_get_deployment_dirpath (self, ret); + struct stat stbuf; + if (!glnx_fstatat (self->sysroot_fd, relpath, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return NULL; + ret->devino_initialized = TRUE; + ret->device = stbuf.st_dev; + ret->inode = stbuf.st_ino; + + return g_steal_pointer (&ret); +} + static gboolean parse_deployment (OstreeSysroot *self, const char *boot_link, OstreeDeployment **out_deployment, GCancellable *cancellable, GError **error) @@ -904,9 +929,6 @@ parse_deployment (OstreeSysroot *self, const char *boot_link, OstreeDeployment * is_booted_deployment = stbuf.st_dev == expected_root_dev && stbuf.st_ino == expected_root_inode; } - gboolean is_soft_reboot_target - = self->have_nextroot - && (stbuf.st_dev == self->nextroot_device && stbuf.st_ino == self->nextroot_inode); g_autoptr (OstreeDeployment) ret_deployment = ostree_deployment_new (-1, osname, treecsum, deployserial, bootcsum, treebootserial); @@ -934,7 +956,10 @@ parse_deployment (OstreeSysroot *self, const char *boot_link, OstreeDeployment * } /* TODO: warn on unknown unlock types? */ } - ret_deployment->soft_reboot_target = is_soft_reboot_target; + + ret_deployment->devino_initialized = TRUE; + ret_deployment->device = stbuf.st_dev; + ret_deployment->inode = stbuf.st_ino; g_debug ("Deployment %s.%d unlocked=%d", treecsum, deployserial, ret_deployment->unlocked); @@ -1179,7 +1204,7 @@ _ostree_sysroot_reload_staged (OstreeSysroot *self, GError **error) if (target) { g_autoptr (OstreeDeployment) staged - = _ostree_sysroot_deserialize_deployment_from_variant (target, error); + = _ostree_sysroot_deserialize_deployment_from_variant (self, target, error); if (!staged) return FALSE; @@ -1312,11 +1337,18 @@ sysroot_load_from_bootloader_configs (OstreeSysroot *self, GCancellable *cancell if (self->staged_deployment) g_ptr_array_insert (deployments, 0, g_object_ref (self->staged_deployment)); - /* And then set their index variables */ + /* Synchronize internal state now that we've loaded all deployments */ for (guint i = 0; i < deployments->len; i++) { OstreeDeployment *deployment = deployments->pdata[i]; ostree_deployment_set_index (deployment, i); + + g_assert (deployment->devino_initialized); + if (self->have_nextroot && deployment->device == self->nextroot_device + && deployment->inode == self->nextroot_inode) + { + deployment->soft_reboot_target = TRUE; + } } /* Determine whether we're "physical" or not, the first time we load deployments */